import * as THREE from "three";
// 导入轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader";
import { DRACOLoader } from "three/examples/jsm/loaders/DRACOLoader";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
// 导入后期效果合成器
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer";
// three框架本身自带效果
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass";
import { SMAAPass } from "three/examples/jsm/postprocessing/SMAAPass";
import { UnrealBloomPass } from "three/examples/jsm/postprocessing/UnrealBloomPass";
import gsap from "gsap";
// 导入海洋
import Ocean from "./Ocean";
// 添加天空球
import SphereSky from "./SphereSky";
export default class ThreePlus {
    constructor(selector) {
        this.actions = [];
        this.textVideoArrays = [];
        this.clock = new THREE.Clock();
        this.domElement = document.querySelector(selector);
        this.width = this.domElement.clientWidth;
        this.height = this.domElement.clientHeight;
        this.updateMeshArr = [];

        this.init();
    }
    init() {
        this.initScene();
        this.initCamera();
        this.initRenderer();
        this.initControl();
        this.initEffect();
        this.render();
    }
    initScene() {
        this.scene = new THREE.Scene();
        this.scene.background = new THREE.Color(0xcccccc);
    }
    initCamera() {
        this.camera = new THREE.PerspectiveCamera(
            45,
            this.width / this.height,
            0.000001,
            10000
        );
        this.camera.position.set(0, 50, 320);

        this.camera.aspect = this.width / this.height;
        //   更新摄像机的投影矩阵
        this.camera.updateProjectionMatrix();
    }
    initRenderer() {
        this.renderer = new THREE.WebGLRenderer({
            logarithmicDepthBuffer: true,
            antialias: true,
            premultipliedAlpha: true,
        });
        this.renderer.setSize(this.width, this.height);
        this.renderer.shadowMap.enabled = true;
        this.renderer.outputEncoding = THREE.sRGBEncoding;
        this.renderer.toneMapping = THREE.ACESFilmicToneMapping;
        this.renderer.toneMappingExposure = 0.3;
        this.renderer.sortObjects = true;
        this.domElement.appendChild(this.renderer.domElement);
    }
    initControl() {
        this.control = new OrbitControls(this.camera, this.renderer.domElement);
        this.control.target.set(0, 15, 0);
    }
    render() {
        this.control && this.control.update();
        this.effectComposer.render();
        requestAnimationFrame(this.render.bind(this));
    }
    gltfLoader(url) {
        const gltfLoader = new GLTFLoader();
        const dracoLoader = new DRACOLoader();
        dracoLoader.setDecoderPath("./draco/gltf/");
        dracoLoader.setDecoderConfig({ type: "js" });
        dracoLoader.preload();
        gltfLoader.setDRACOLoader(dracoLoader);

        return new Promise((resolve, reject) => {
            gltfLoader.load(url, (gltf) => {
                resolve(gltf);
            });
        });
    }
    hdrLoader(url) {
        const hdrLoader = new RGBELoader();
        return new Promise((resolve, reject) => {
            hdrLoader.load(url, (hdr) => {
                resolve(hdr);
            });
        });
    }
    setBg(url) {
        return new Promise((resolve, reject) => {
            this.hdrLoader(url).then((texture) => {
                texture.mapping = THREE.EquirectangularRefractionMapping;
                texture.anisotropy = 16;
                texture.format = THREE.RGBAFormat;
                this.scene.background = texture;
                this.scene.environment = texture;
                resolve(texture);
            });
        });
    }
    initEffect() {
        // 合成效果
        this.effectComposer = new EffectComposer(this.renderer);
        this.effectComposer.setSize(window.innerWidth, window.innerHeight);

        // 添加渲染通道
        const renderPass = new RenderPass(this.scene, this.camera);
        this.effectComposer.addPass(renderPass);

        // 抗锯齿
        const smaaPass = new SMAAPass(
            window.innerWidth * this.renderer.getPixelRatio(),
            window.innerHeight * this.renderer.getPixelRatio()
        );
        this.effectComposer.addPass(smaaPass);

        // 发光效果
        this.unrealBloomPass = new UnrealBloomPass();
        this.unrealBloomPass.enabled = false;
        this.unrealBloomPass.threshold = 0.1;
        this.unrealBloomPass.strength = 1;
        this.unrealBloomPass.radius = 2;
        this.effectComposer.addPass(this.unrealBloomPass);

    }
    // 添加海洋
    addOcean() {
        let ocean = new Ocean();
        this.scene.add(ocean.mesh);
    }
    // 添加辅助坐标轴
    addAxis() {
        let axis = new THREE.AxesHelper(20);
        this.scene.add(axis);
    }
    // 添加天空球
    addSphereSky(dayCallback, nightCallback) {
        let uTime = {
            value: 0,
        };
        this.isDay = true;
        let sphereSky = new SphereSky(10000, uTime, this.scene.environment);
        this.scene.add(sphereSky.mesh, sphereSky.sun);

        // 动态修改时间
        gsap.to(uTime, {
            value: 24,
            duration: 24,
            repeat: -1,
            ease: "linear",
            onUpdate: () => {
                sphereSky.updateSun(uTime.value);
                if (uTime.value > 6 && uTime.value <= 18 && this.isDay == false) {
                    sphereSky.sun.visible = true;
                    this.isDay = true;
                    dayCallback();
                }
                // console.log(this.isDay);
                if ((uTime.value > 18 || uTime.value <= 6) && this.isDay == true) {
                    this.isDay = false;
                    sphereSky.sun.visible = false;
                    // console.log(this.isDay);
                    nightCallback();
                }
                if (Math.abs(uTime.value - 12) < 4) {
                    this.renderer.toneMappingExposure = 1;
                }
                if (Math.abs(uTime.value - 12) > 6) {
                    this.renderer.toneMappingExposure = 0.3;
                }
                if (
                    Math.abs(uTime.value - 12) >= 4 &&
                    Math.abs(uTime.value - 12) <= 6
                ) {
                    let strength = 1 - (Math.abs(uTime.value - 12) - 4) / 2;
                    strength < 0.3 ? (strength = 0.3) : (strength = strength);
                    this.renderer.toneMappingExposure = strength;
                }
            },
        });
        return sphereSky;
    }
}
